package cn.edu.njnu.opengmpback.common.service;

import it.geosolutions.geoserver.rest.GeoServerRESTManager;
import it.geosolutions.geoserver.rest.GeoServerRESTReader;
import it.geosolutions.geoserver.rest.decoder.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * GeoServer边界获取服务
 * 专门处理地理数据边界信息的获取
 * 支持栅格数据(TIFF)和矢量数据(Shapefile, Vec等)
 * 
 * @author Claude
 * @date 2024-08-20
 */
@Slf4j
@Service
public class GeoServerBoundsService {

    @Value("${geoserver.url}")
    private String geoServerUrl;

    @Value("${geoserver.username}")
    private String geoServerUsername;

    @Value("${geoserver.password}")
    private String geoServerPassword;

    /**
     * 获取已发布图层的地理边界范围
     * 支持多种数据类型：TIFF栅格数据、Shapefile矢量数据、Vec矢量数据等
     * 
     * @param workSpace 工作空间名称
     * @param layerName 图层名称
     * @return 包含边界信息的Map对象，如果失败返回null
     */
    public Map<String, Double> getLayerBounds(String workSpace, String layerName) {
        log.info("🔍 开始获取图层边界信息: workspace={}, layer={}", workSpace, layerName);
        
        try {
            GeoServerRESTManager manager = new GeoServerRESTManager(new URL(geoServerUrl), geoServerUsername, geoServerPassword);
            GeoServerRESTReader reader = manager.getReader();
            
            // 获取图层详细信息
            RESTLayer layer = reader.getLayer(workSpace, layerName);
            if (layer != null) {
                log.info("✅ 成功获取图层信息: {}", layer.getName());
                
                // 🎯 策略1: 尝试获取Coverage详细信息 (适用于TIFF等栅格数据)
                Map<String, Double> coverageBounds = getCoverageBounds(reader, workSpace, layer, layerName);
                if (coverageBounds != null) {
                    return coverageBounds;
                }
                
                // 🎯 策略2: 尝试获取FeatureType详细信息 (适用于Shapefile、Vec等矢量数据)
                Map<String, Double> featureBounds = getFeatureTypeBounds(reader, layer);
                if (featureBounds != null) {
                    return featureBounds;
                }
                
                // 🎯 策略3: 尝试通过DataStore获取边界 (兜底方案)
                Map<String, Double> datastoreBounds = getDataStoreBounds(reader, workSpace, layerName);
                if (datastoreBounds != null) {
                    return datastoreBounds;
                }
                
            } else {
                log.warn("❌ 未找到图层: {} in workspace: {}", layerName, workSpace);
            }
        } catch (Exception e) {
            log.error("❌ 获取图层边界失败: {}", e.getMessage(), e);
        }
        
        log.warn("❌ 无法获取图层边界信息");
        return null;
    }

    /**
     * 获取Coverage（栅格数据）边界信息
     * 适用于: TIFF, GeoTIFF, IMG等栅格格式
     */
    private Map<String, Double> getCoverageBounds(GeoServerRESTReader reader, String workSpace, RESTLayer layer, String layerName) {
        try {
            log.info("📊 尝试获取Coverage边界信息...");
            RESTCoverage coverage = reader.getCoverage(workSpace, layer.getName(), layerName);
            
            if (coverage != null && coverage.getLatLonBoundingBox() != null) {
                RESTBoundingBox bbox = coverage.getLatLonBoundingBox();
                
                log.info("📊 获取到Coverage边界信息:");
                log.info("   📍 minLon: {}", bbox.getMinX());
                log.info("   📍 minLat: {}", bbox.getMinY());
                log.info("   📍 maxLon: {}", bbox.getMaxX());
                log.info("   📍 maxLat: {}", bbox.getMaxY());
                log.info("   📍 坐标系: {}", bbox.getCRS());
                
                Map<String, Double> bounds = new HashMap<>();
                bounds.put("minLon", bbox.getMinX());
                bounds.put("minLat", bbox.getMinY());
                bounds.put("maxLon", bbox.getMaxX());
                bounds.put("maxLat", bbox.getMaxY());
                
                return bounds;
            } else {
                log.info("⚠️ Coverage信息为空或无边界信息");
            }
        } catch (Exception coverageEx) {
            log.info("ℹ️ 无法获取Coverage信息，可能不是栅格数据: {}", coverageEx.getMessage());
        }
        return null;
    }

    /**
     * 获取FeatureType（矢量数据）边界信息  
     * 适用于: Shapefile, Vec, GeoJSON, KML等矢量格式
     */
    private Map<String, Double> getFeatureTypeBounds(GeoServerRESTReader reader, RESTLayer layer) {
        try {
            log.info("📊 尝试获取FeatureType边界信息...");
            RESTFeatureType featureType = reader.getFeatureType(layer);
            
            if (featureType != null && featureType.getLatLonBoundingBox() != null) {
                RESTBoundingBox bbox = featureType.getLatLonBoundingBox();
                
                log.info("📊 获取到FeatureType边界信息:");
                log.info("   📍 minLon: {}", bbox.getMinX());
                log.info("   📍 minLat: {}", bbox.getMinY());
                log.info("   📍 maxLon: {}", bbox.getMaxX());
                log.info("   📍 maxLat: {}", bbox.getMaxY());
                log.info("   📍 坐标系: {}", bbox.getCRS());
                
                Map<String, Double> bounds = new HashMap<>();
                bounds.put("minLon", bbox.getMinX());
                bounds.put("minLat", bbox.getMinY());
                bounds.put("maxLon", bbox.getMaxX());
                bounds.put("maxLat", bbox.getMaxY());
                
                return bounds;
            } else {
                log.info("⚠️ FeatureType信息为空或无边界信息");
            }
        } catch (Exception featureEx) {
            log.info("ℹ️ 无法获取FeatureType信息: {}", featureEx.getMessage());
        }
        return null;
    }

    /**
     * 通过DataStore获取边界信息（兜底方案）
     * 适用于特殊格式或其他获取方式失败的情况
     */
    private Map<String, Double> getDataStoreBounds(GeoServerRESTReader reader, String workSpace, String layerName) {
        try {
            log.info("📊 尝试通过DataStore获取边界信息...");
            
            // 这里可以添加更多的获取策略
            // 比如直接读取文件头信息、调用GDAL等
            
            log.info("ℹ️ DataStore方案暂未实现，可扩展");
        } catch (Exception e) {
            log.warn("⚠️ DataStore获取边界失败: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 检查数据类型并返回处理建议
     * 
     * @param fileName 文件名
     * @return 数据类型信息
     */
    public String getDataTypeInfo(String fileName) {
        String extension = fileName.toLowerCase();
        
        if (extension.endsWith(".tif") || extension.endsWith(".tiff")) {
            return "栅格数据 - TIFF格式，适合遥感影像、DEM等连续数据";
        } else if (extension.endsWith(".shp")) {
            return "矢量数据 - Shapefile格式，适合点线面要素数据";
        } else if (extension.endsWith(".vec")) {
            return "矢量数据 - Vec格式，需要特殊处理，建议转换为Shapefile";
        } else if (extension.endsWith(".geojson")) {
            return "矢量数据 - GeoJSON格式，Web友好的矢量格式";
        } else if (extension.endsWith(".kml") || extension.endsWith(".kmz")) {
            return "矢量数据 - KML格式，Google Earth标准格式";
        }
        
        return "未知格式 - 请确认数据类型";
    }

    /**
     * 🎯 Vec矢量数据特殊处理建议
     * Vec格式是一些GIS软件的专有格式，处理方式：
     * 
     * 1. 转换方案：使用GDAL/OGR转换为标准格式
     * 2. 直接支持：如果GeoServer支持该格式
     * 3. 解析方案：自定义解析器读取头文件获取边界
     */
    public Map<String, String> getVecProcessingAdvice(String fileName) {
        Map<String, String> advice = new HashMap<>();
        
        advice.put("format", "Vec矢量格式");
        advice.put("recommendation", "建议转换为Shapefile或GeoJSON格式");
        advice.put("tools", "可使用GDAL ogr2ogr工具进行转换");
        advice.put("command", "ogr2ogr -f \"ESRI Shapefile\" output.shp input.vec");
        advice.put("alternative", "如果无法转换，可尝试直接上传到GeoServer测试兼容性");
        
        return advice;
    }
}